package org.example.demo;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;

import java.util.Map;

import static org.example.demo.SqlValidator.formatSQL;


public class CheckSqlSyntaxAction extends AnAction {

    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        Editor editor = e.getData(CommonDataKeys.EDITOR);
        PsiFile file = e.getData(CommonDataKeys.PSI_FILE);

        if (project == null || editor == null || file == null) {
            Messages.showMessageDialog(project, "环境不完整", "SQL 检查", Messages.getErrorIcon());
            return;
        }

        int offset = editor.getCaretModel().getOffset();

        // ✅ 在 ReadAction 中访问 PSI
        String resultMessage = ReadAction.compute(() -> {
            try {
                PsiElement element = file.findElementAt(offset);
                if (element == null) return "ERROR: 无法确定当前位置";

                XmlText xmlText = PsiTreeUtil.getParentOfType(element, XmlText.class);
                if (xmlText == null) return "ERROR: 请将光标放在 SQL 语句内";

                XmlTag parentTag = PsiTreeUtil.getParentOfType(xmlText, XmlTag.class);
                if (parentTag == null) return "ERROR: 无法找到 SQL 标签";

                String tagName = parentTag.getName();
                if (!tagName.matches("(?i)^(select|update|insert|delete)$")) {
                    return "ERROR: 仅支持在 <select>/<update>/<insert>/<delete> 标签内使用";
                }

                String sqlContent = xmlText.getValue().trim();
                if (sqlContent.isEmpty()) return "ERROR: SQL 内容为空";

                String error = SqlValidator.validate(sqlContent);
                String formatSQL = formatSQL(sqlContent);
                 if (error==null){
                     // 语法正确，询问是否执行
                     int choice = Messages.showYesNoDialog(
                             project,
                             "SQL 语法正确！是否使用配置的数据源执行该 SQL？\n（仅用于测试，#{id} 已替换为 -1）",
                             "执行 SQL",
                             Messages.getQuestionIcon()
                     );

                     if (choice == Messages.YES) {
                         // 模拟替换 #{xxx} 为 -1
                         String parsedSql = formatSQL.replaceAll("\\#\\{[^}]+\\}", "'-1'").trim();

                         // 执行 SQL
                         SqlExecutor.Result result = SqlExecutor.execute(project, parsedSql);

                         // 显示结果
                         showExecutionResult(project, result, parsedSql);
                     } else {
                         Messages.showMessageDialog(project, "OK: SQL 语法正确！", "人大金仓 SQL 检查", Messages.getInformationIcon());
                     }


                 }

                return error == null ? "OK: SQL 语法正确！" : "ERROR: " + error;
            } catch (Exception ex) {
                return "ERROR: " + ex.getMessage();
            }
        });

//        // 弹窗提示
//        if (resultMessage.startsWith("OK:")) {
//            Messages.showMessageDialog(project, resultMessage.substring(4), "人大金仓 SQL 语法检查", Messages.getInformationIcon());
//        } else if (resultMessage.startsWith("ERROR:")) {
//            Messages.showMessageDialog(project, resultMessage.substring(7), "人大金仓 SQL 语法检查", Messages.getErrorIcon());
//        }
    }

    @Override
    public void update(@NotNull AnActionEvent e) {
        Project project = e.getProject();
        Editor editor = e.getData(CommonDataKeys.EDITOR);

        boolean enabled = project != null && editor != null;
        if (enabled) {
            // 通过 Document 获取 VirtualFile（比直接 getData 更安全？但仍有风险）
            var document = editor.getDocument();
            var virtualFile = FileDocumentManager.getInstance().getFile(document);
            if (virtualFile != null) {
                enabled = virtualFile.getName().toLowerCase().endsWith(".xml");
            } else {
                // 未保存的文件 or 无关联文件，禁用
                enabled = false;
            }
        }

        e.getPresentation().setEnabled(enabled);
    }




    private void showExecutionResult(Project project, SqlExecutor.Result result, String sql) {
        StringBuilder msg = new StringBuilder();

        if (result.success) {
            msg.append("✅ 执行成功\n");
            msg.append("耗时: ").append(result.duration).append("ms\n\n");

            if (result.isQuery) {
                msg.append("【查询结果】\n");
                if (result.rows.isEmpty()) {
                    msg.append("(无数据)\n");
                } else {
                    msg.append(String.join(" | ", result.columns)).append("\n");
                    msg.append("-".repeat(Math.min(80, msg.length()))).append("\n");
                    for (Map<String, Object> row : result.rows) {
                        for (String col : result.columns) {
                            Object val = row.get(col);
                            msg.append(val == null ? "NULL" : val.toString()).append(" | ");
                        }
                        msg.delete(msg.length() - 3, msg.length()).append("\n");
                    }
                }
            } else {
                msg.append("类型: 更新/DDL\n");
                msg.append("影响行数: ").append(result.affectedRows).append("\n");
            }
        } else {
            // ❌ 执行失败，显示错误
            msg.append("❌ 执行失败！\n\n");
            msg.append("SQL: \n").append(sql).append("\n\n");
            msg.append("错误信息: \n").append(result.message != null ? result.message : "未知错误");
        }

        // 统一弹窗
        Messages.showMessageDialog(
                project,
                msg.toString(),
                "SQL 执行结果",
                result.success ? Messages.getInformationIcon() : Messages.getErrorIcon()
        );
    }
}